﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

using JupiterLibrary;
using KinnectInput.KinectIcons;
using Microsoft.Research.Kinect.Nui;
using KinectXNATools;
using KinnectInput.KinectMetro;

namespace KinnectInput
{
    public class KinectInputInterpreter
    {
        #region fields
        public SkeletalManager skell { get; private set; }
        
        public KinectFlatInteraction flatHands{get; private set;}
        public KinectCuadrantDebuger realtiveSpace;
        public KinectMetroMenu MetroMenu { get; private set; }
        public JupiterLibrary.Camera cam { get; set; }
        
        bool StillInMenu;
        public Vector3 PositionHandASecondAgo { get; set; }
        public bool move { get; private set; }
        GameTime gameTime;
        
        #endregion fields

        #region constructor
        public KinectInputInterpreter(SkeletalManager skell, GraphicsDevice gDev, JupiterLibrary.Camera cam)
        {
            this.skell=skell;
            Texture2D manoTex = Jupiter.Content.Load<Texture2D>("UI/ManoSprite");
            flatHands = new KinectFlatInteraction(skell,gDev);
            flatHands.HandTex = manoTex;
            realtiveSpace = new KinectCuadrantDebuger(gDev, flatHands);
            Rectangle MetroMenuRect=new Rectangle(0,0,gDev.Viewport.Width, gDev.Viewport.Height);
            //Texture2D texMenu=Texture2DHelper.TextureFromColor(gDev, MetroMenuRect, Color.Pink);
            Texture2D texMenu = Jupiter.Content.Load<Texture2D>("MenuBackground/DeskTopBackGround");
            MetroMenu = new KinectMetroMenu(texMenu, MetroMenuRect, gDev, skell.MainUser, manoTex);
            MetroMenu.FillButtonGroup(Jupiter.Content.Load<Texture2D>("Icons/Plane"), new string[]{"Click Here","To Book Your Flight"}, gDev);
            MetroMenu.FillButtonGroup(Jupiter.Content.Load<Texture2D>("Icons/Hotel"), new string[]{"Click Here For", "Hotel Bookings"}, gDev);
            MetroMenu.FillButtonGroup(Jupiter.Content.Load<Texture2D>("Icons/Info"), new string[]{"Click Here To","Watch Video"}, gDev);
            MetroMenu.FillButtonGroup(Jupiter.Content.Load<Texture2D>("Icons/Computer"), new string[]{"Click Here To","Send To Your PC"}, gDev);
            MetroMenu.FillButtonGroup(Jupiter.Content.Load<Texture2D>("Icons/Car"), new string[]{"Click Here For","CarRental"}, gDev);
            MetroMenu.FillButtonGroup(Jupiter.Content.Load<Texture2D>("Icons/WindowsPhone"), new string[]{"Click Here To","Send To","Windows Phone"}, gDev);
            this.cam = cam;
            
            
        }
        #endregion constructor

        public void Initialize()
        {
            skell.MainUser.MainUserChanged += new KinectUserManager.MainUserChangeEventHandler(MainUser_MainUserChanged);
            skell.MainUser.NewUserFound += new KinectUserManager.NewUserEventHandler(MainUser_NewUserFound);
            skell.MainUser.UserLost += new KinectUserManager.UserLostEventHandler(MainUser_UserLost);
            skell.MainUser.UserClipped += new KinectUserManager.UserClippedEventHandler(MainUser_UserClipped);
            skell.MainUser.UserCompleted += new KinectUserManager.UserCompletedEventHandler(MainUser_UserCompleted);
            skell.MainUser.SecondUserFound += new KinectUserManager.SecondUserEventHandler(MainUser_SecondUserFound);
            this.MetroMenu.Inicialize(skell.MainUser);
            
        }

        #region events
        void MainUser_UserCompleted(object sender, KinectUserManager.UserCompletedEventArgs e)
        {
            skell.ActiveUserState = UserState.Active;
        }

        void MainUser_SecondUserFound(object sender, KinectUserManager.SecondUserFoundEventArgs e)
        {
            skell.ActiveUserState = UserState.TwoUsers;
        }

        void MainUser_UserClipped(object sender, KinectUserManager.UserClippedEventArgs e)
        {
            if (MetroMenu.MenuState == KinectMetroMenuState.Colapsed)
            {
                skell.ActiveUserState = UserState.UserClipped;
                switch (e.UserClipping)
                {
                    case SkeletonQuality.ClippedBottom:
                        skell.ClippedMessage = "Your Legs are Invisble";
                        break;
                    case SkeletonQuality.ClippedLeft:
                        skell.ClippedMessage = "Step Right Back in to the vision area please";
                        break;
                    case SkeletonQuality.ClippedRight:
                        skell.ClippedMessage = "Step Left Back in to the vision area please";
                        break;
                    case SkeletonQuality.ClippedTop:
                        skell.ClippedMessage = "Step Back you are to Close to the sensor";
                        break;
                    default:
                        skell.ClippedMessage = "UnDefined Cliping";
                        break;
                }
            }
        }

        void MainUser_UserLost(object sender, KinectUserManager.UserLostEventArgs e)
        {
            //if (this.MenuWindow.MenuState== KinectMenuState.Active)
            if (!skell.IsKinectDistance && MetroMenu.MenuState == KinectMetroMenuState.Active)
            {
                skell.ActiveUserState = UserState.Active;
            }
            else if(skell.MainUser.nTrackedUsers>0){
                skell.ActiveUserState = UserState.Active;
            }
            else
            {
                skell.ActiveUserState = UserState.NoUser;
                MetroMenu.MenuState = KinectMetroMenuState.Colapsed;
            }
        }

        void MainUser_NewUserFound(object sender, KinectUserManager.NewUserEventArgs e)
        {
            skell.ActiveUserState = UserState.Active;
            realtiveSpace.Update(skell.JointPosition[JointID.Head], skell.JointPosition[JointID.HipCenter], this.gameTime,true);
        }

        void MainUser_MainUserChanged(object sender, KinectUserManager.MainUserChangedEventArgs e)
        {
            this.realtiveSpace._finalState = KinectInputState.Still;
            skell.ActiveUserState = UserState.Active;
            MetroMenu.MenuState = KinectMetroMenuState.Active;
            //this.StillInMenu = true;
        }
        #endregion events
        
        float timeForSecond;

        public void Update(GameTime gameTime)
        {
            this.gameTime = gameTime;
            if (skell.IsKinectDistance)
            {
                flatHands.Update();
                timeForSecond += Jupiter.At1Second(2);
                if (timeForSecond >= 1)
                {
                    timeForSecond -= 1;
                    Vector3 oldOne = this.PositionHandASecondAgo;
                    Vector3 newOne;
                    if (skell.MainUser.PlayerOneJoints == null || skell.MainUser.PlayerOneJoints.Count < 1)
                        newOne = new Vector3(0,5,0);
                    else
                        newOne = XNAMathHelper.XYZtoVector3( skell.MainUser.PlayerOneJoints[JointID.HandRight]);
                    float length = oldOne.X - newOne.X;
                    if (Math.Abs(length) > 0.5)
                    {
                        this.move = true;
                    }
                    else
                    {
                        this.move = false;
                    }
                    this.PositionHandASecondAgo = newOne;

                }
                realtiveSpace.Update(skell.JointPosition[JointID.Head], skell.JointPosition[JointID.HipCenter], gameTime, MetroMenu.MenuState == KinectMetroMenuState.Active);
                
            }
            //Esto es lo que evitava que se produciera update, por el kinect distance
            MetroMenu.Update(overHeard());
        }
        //Tengo que dibujar el iconito desde fuera o sale en el fondo con todo el 3d por enmedio
        public void Draw()
        {
            MetroMenu.Draw();
        }
        public void Draw(SpriteBatch sb, SpriteFont sf)
        {
           if (this.MetroMenu.MenuState == KinectMetroMenuState.Active)
            {
                //gazapo para que cuando salga el video no sep inten las lineas encima
                if (!MetroMenu.InfoVideoPlayer.isVisible)
                {
                    this.MetroMenu.DrawTextButtons(sb, sf);
                }
            }
        }
        private bool overHeard()
        {
            if (skell == null || skell.MainUser == null || skell.MainUser.PlayerOneJoints == null || skell.MainUser.PlayerOneJoints.Count < 1)
                return false;
            float modulo = skell.MainUser.PlayerOneJoints[JointID.ElbowRight].Y - skell.MainUser.PlayerOneJoints[JointID.Head].Y;
            float overHead= skell.MainUser.PlayerOneJoints[JointID.HandRight].Y - skell.MainUser.PlayerOneJoints[JointID.Head].Y;
            float handTilt = skell.MainUser.PlayerOneJoints[JointID.HandRight].X - skell.MainUser.PlayerOneJoints[JointID.ElbowRight].X;
            
            modulo = Math.Abs(modulo);
            handTilt = Math.Abs(handTilt);
            if (modulo < 0)
            {
                return false;
            }
            else if (modulo < 0.45f && overHead > 0.051f && handTilt < 0.1f)
            {

                return true;
            }
            else
                return false;
            
        }
        

    }
}
